package com.cecil.generate.factory;

import com.cecil.generate.constants.GlobalProperties;
import com.cecil.generate.domain.Table;
import com.cecil.generate.util.StringUtil;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.List;

@Slf4j
public enum ClassTypeEnum {

    DOMAIN("domain", "", "entity.ftl", "baseEntity.ftl", "BaseEntity.java"),
    MAPPER("mapper", "Mapper", "mapper.ftl", "", ""),
    SERVICE("service", "Service", "service.ftl", "", "") {
        @Override
        protected String getFileName(Table table, GlobalProperties properties) {
            return properties.getServiceInterfacePrefix() + super.getFileName(table, properties);
        }
    },
    SERVICE_IMPL("serviceImpl", "ServiceImpl", "serviceImpl.ftl", "", "") {
        @Override
        protected String getFilePath(String dist) {
            return dist + File.separator + SERVICE.value;
        }

        @Override
        protected File generateFile(String modulePath, Table table, GlobalProperties properties) {
            return new File(modulePath + File.separator + "impl" + File.separator + getFileName(table, properties) + ".java");
        }
    },
    CONTROLLER("controller", "Controller", "controller.ftl", "baseController.ftl", "BaseController.java"),
    MAPPER_XML("", "Mapper", "mapperXml.ftl", "", "") {
        @Override
        protected File generateFile(String modulePath, Table table, GlobalProperties properties) {
            return new File(modulePath + File.separator + getFileName(table, properties) + ".xml");
        }
    },
    CONVERT("convert", "Converter", "convert.ftl", "", "") {};

    public final String value;
    public final String classNameSuffix;
    public final String templates;
    public final String baseTemplates;
    public final String baseClassName;

    ClassTypeEnum(String value, String classNameSuffix, String templates, String baseTemplates, String baseClassName) {
        this.value = value;
        this.classNameSuffix = classNameSuffix;
        this.templates = templates;
        this.baseTemplates = baseTemplates;
        this.baseClassName = baseClassName;
    }

    protected String getFilePath(String dist) {
        return dist + File.separator + this.value;
    }

    protected String getFileName(Table table, GlobalProperties properties) {
        return table.getClassName() + this.classNameSuffix;
    }

    protected String getModulePath(String filePath, GlobalProperties properties) {
        String module = properties.getModule();
        if (StringUtil.isNotEmpty(module)) {
            return filePath + File.separator + module;
        }
        return filePath;
    }

    protected void addMapProps(LinkedHashMap<String, Object> map, Table table, GlobalProperties properties) {
        map.put("serviceClassName", SERVICE.getFileName(table, properties));
    }

    protected File generateFile(String modulePath, Table table, GlobalProperties properties) {
        return new File(modulePath + File.separator + getFileName(table, properties) + ".java");
    }

    public void generate(String dist,
                         Configuration cfg,
                         List<Table> tables,
                         LinkedHashMap<String, Object> map,
                         GlobalProperties properties) throws IOException {
        String filePath = getFilePath(dist);
        String modulePath = getModulePath(filePath, properties);

        if (StringUtil.isNotEmpty(this.baseTemplates)) {
            Template template = cfg.getTemplate(this.baseTemplates);
            File file = new File(filePath + File.separator + this.baseClassName);
            writeFile(file, template, map);
        }

        Template template = cfg.getTemplate(this.templates);
        for (Table table : tables) {
            map.put("table", table);
            map.put("fileName", getFileName(table, properties));
            addMapProps(map, table, properties);
            File file = generateFile(modulePath, table, properties);
            writeFile(file, template, map);
        }
    }

    private static void writeFile(File file, Template template, LinkedHashMap<String, Object> map) {
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        try (FileWriter out = new FileWriter(file)) {
            template.process(map, out);
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static ClassTypeEnum[] javaTemplates() {
        return new ClassTypeEnum[]{DOMAIN, MAPPER, SERVICE, SERVICE_IMPL, CONTROLLER, CONVERT};
    }
}
